﻿
using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
using DigitalRune.Windows.Docking;
using md.imi.membrane.constants;
using md.imi.membranes.gui.Dialogs;
using md.imi.membranes.gui.Editor;
using md.imi.membranes.gui.Info;
using md.imi.membranes.gui.Navigation;
using md.imi.membranes.objects;
using md.imi.membranes.objects.alphabet;
using md.imi.membranes.objects.membranes;
using md.imi.membranes.objects.psystems;
using md.imi.membranes.objects.rules;
using md.imi.membranes.objects.strings;

namespace md.imi.membranes.gui
{
    /// <summary>
    ///     Main form
    /// </summary>
    public partial class MainForm : Form
    {
        #region Properties
        private CurrentConfigurationTree _navigationForm = null;
        private AvailableTransitions _solutionsForm = null;
        private ComputationTree _computationTree = null;
        private LogsView _logsView = null;
        private GeneratedLanguageView _generatedLanguageView = null;
        private ConfigDiffsView _configDiffView = null;

        //	 TODO: Define a set of reserved memebrane names/labels
        public const String ENV_NAME = "Environment";
        public const string APPLICATION_NAME = @"PSSOSim";

        #endregion

        #region Constructor
        // TODO: Q1 - the right hand rule should contain the resulting multiset ? (string object)
        public MainForm()
        {
            InitializeComponent();
        }
        #endregion

        #region Demo project cteation
        /// <summary>
        ///     Create a testing demo system
        /// </summary>
        /// <returns></returns>
        private PSystemsTree CreateNewDemoPSystem()
        {
            // create a default pSystem (for testing purpose)
            // define multiset which is the same for all membranes
            var multiset = new List<StringObject>();
            multiset.Add(new StringObject());
            multiset[0].Add(new AlphabetObject("a"));
            multiset[0].Add(new AlphabetObject("bc"));
            multiset[0].Add(new AlphabetObject("d"));

            multiset.Add(new StringObject());
            multiset[1].Add(new AlphabetObject("e1"));
            multiset[1].Add(new AlphabetObject("e2"));
            multiset[1].Add(new AlphabetObject("e4"));

            //**************************************************************
            // Rule for membrane A
            var rule1 = new ReplicationRule() { Label = "RA1" };
            rule1.LeftHandRule.SubstringPattern = new StringObject();
            rule1.LeftHandRule.SubstringPattern.Add(new AlphabetObject("bc"));
            // r1.1
            rule1.RightHandRules.Add(new RightHandRule());
            rule1.RightHandRules[0].TargetType = RuleTargets.Here;
            rule1.RightHandRules[0].Result = new StringObject();
            rule1.RightHandRules[0].Result.Add(new AlphabetObject("c"));

            // r1.2
            rule1.RightHandRules.Add(new RightHandRule());
            rule1.RightHandRules[1].TargetType = RuleTargets.Out;
            rule1.RightHandRules[1].Result = new StringObject();
            rule1.RightHandRules[1].Result.Add(new AlphabetObject("ad"));

            //**************************************************************
            // Rule for membrane B
            var rule2 = new ReplicationRule() { Label = "RB1" };
            rule2.LeftHandRule.SubstringPattern = new StringObject();
            rule2.LeftHandRule.SubstringPattern.Add(new AlphabetObject("e1"));

            rule2.RightHandRules.Add(new RightHandRule());
            rule2.RightHandRules[0].TargetType = RuleTargets.Here;
            rule2.RightHandRules[0].Result = new StringObject();
            rule2.RightHandRules[0].Result.Add(new AlphabetObject("d1"));

            rule2.RightHandRules.Add(new RightHandRule());
            rule2.RightHandRules[1].TargetType = RuleTargets.Out;
            rule2.RightHandRules[1].Result = new StringObject();
            rule2.RightHandRules[1].Result.Add(new AlphabetObject("d2"));

            //**************************************************************
            // Rule for memebrane C
            var rule3 = new ReplicationRule() { Label = "RC1" };
            rule3.LeftHandRule.SubstringPattern = new StringObject();
            rule3.LeftHandRule.SubstringPattern.Add(new AlphabetObject("d"));

            rule3.RightHandRules.Add(new RightHandRule());
            rule3.RightHandRules[0].TargetType = RuleTargets.Here;
            rule3.RightHandRules[0].Result = new StringObject();
            rule3.RightHandRules[0].Result.Add(new AlphabetObject("d4"));

            rule3.RightHandRules.Add(new RightHandRule());
            rule3.RightHandRules[1].TargetType = RuleTargets.Out;
            rule3.RightHandRules[1].Result = new StringObject();
            rule3.RightHandRules[1].Result.Add(new AlphabetObject("d5"));

            //**************************************************************
            // Rule for memebrane C (II)

            var rule5 = new ReplicationRule() { Label = "RC2" };
            rule5.LeftHandRule.SubstringPattern = new StringObject();
            rule5.LeftHandRule.SubstringPattern.Add(new AlphabetObject("d"));

            rule5.RightHandRules.Add(new RightHandRule());
            rule5.RightHandRules[0].TargetType = RuleTargets.Here;
            rule5.RightHandRules[0].Result = new StringObject();
            rule5.RightHandRules[0].Result.Add(new AlphabetObject("a"));

            rule5.RightHandRules.Add(new RightHandRule());
            rule5.RightHandRules[1].TargetType = RuleTargets.Here;
            rule5.RightHandRules[1].Result = new StringObject();
            rule5.RightHandRules[1].Result.Add(new AlphabetObject("e4"));

            //**************************************************************
            // Rule for membrane B (II)
            var rule4 = new ReplicationRule() { Label = "RB2" };
            rule4.LeftHandRule.SubstringPattern = new StringObject();
            rule4.LeftHandRule.SubstringPattern.Add(new AlphabetObject("a"));
            // r4.1
            rule4.RightHandRules.Add(new RightHandRule());
            rule4.RightHandRules[0].TargetMembraneLabel = "C";
            rule4.RightHandRules[0].TargetType = RuleTargets.In;
            rule4.RightHandRules[0].Result = new StringObject();
            rule4.RightHandRules[0].Result.Add(new AlphabetObject("e1"));
            rule4.RightHandRules[0].Result.Add(new AlphabetObject("e2"));

            // r4.2
            rule4.RightHandRules.Add(new RightHandRule());
            rule4.RightHandRules[1].TargetType = RuleTargets.Here;
            rule4.RightHandRules[1].Result = new StringObject();
            rule4.RightHandRules[1].Result.Add(new AlphabetObject("e4"));

            // r4.3
            rule4.RightHandRules.Add(new RightHandRule());
            rule4.RightHandRules[2].TargetType = RuleTargets.Out;
            rule4.RightHandRules[2].Result = new StringObject();
            rule4.RightHandRules[2].Result.Add(new AlphabetObject("d"));

            // define membrane structures.
            // P Sytem already contains an environment membrane
            // THere are also 3 membranes A, B, C.  A and B are in inverenment, and the C is in B
            var membraneA = new MembranesTree()
            {
                Configuration = WorkSpace.Instance.SelectedProject,
                Label = "A"
            };

            membraneA.Multiset.AddRange(multiset);
            membraneA.Rules.Add(rule1);

            var membraneB = new MembranesTree()
            {
                Configuration = WorkSpace.Instance.SelectedProject,
                Label = "B"
            };
            membraneB.Multiset.AddRange(multiset);
            membraneB.Rules.Add(rule2);
            membraneB.Rules.Add(rule4);

            var membraneC = new MembranesTree()
            {
                Configuration = WorkSpace.Instance.SelectedProject,
                Label = "C"
            };

            membraneC.Multiset.AddRange(multiset);
            membraneC.Rules.Add(rule3);
            membraneC.Rules.Add(rule5);

            membraneB.Membranes.Add(membraneC);

            var pSystem = new PSystemsTree();
            pSystem.Membranes.Membranes.Add(membraneA);
            pSystem.Membranes.Membranes.Add(membraneB);
            pSystem.ProjectName = "conf-0";
            pSystem.ProjectName = null;
            LogsView.Info("Generation of pSystem finished");
            return pSystem;
        }


        private PSystemsTree CreateNewEmptyPSystem()
        {
            var pSystem = new PSystemsTree {ProjectName = "conf-0"};
            pSystem.ProjectName = null;
            LogsView.Info("Generation of New Empty pSystem finished");
            return pSystem;
        }
        #endregion

        #region Menu action handlers
        /// <summary>
        ///     Handle main menu items click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainMenuItemClick(object sender, EventArgs e)
        {
            // ------------------------------------------------------------------------------------
            //  Calculate paths - and update solutions form
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("toolsCalculatePaths"))
            {
                if (WorkSpace.Instance.SelectedProject != null && 
                    !WorkSpace.Instance.SelectedProject.CalculateNextPath())
                {
                    FrmMessageBox.ShowInfo("No more paths to calculate!");
                }
                else
                {
                    if (_solutionsForm != null && WorkSpace.Instance.SelectedProject != null)
                    {
                        _solutionsForm.UpdatePsystemSelection(WorkSpace.Instance.SelectedProject.EditorForm, null);
                    }

                    if (_computationTree != null  && WorkSpace.Instance.SelectedProject != null)
                    {
                        _computationTree.UpdateComputationTree(WorkSpace.Instance.SelectedProject);
                    }

                    LogsView.Info("Paths calculated");
                }
            }

            // ------------------------------------------------------------------------------------
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("fileNew"))
            {
                CreateEditorFormForSolution(/*CreateNewDemoPSystem()*/ CreateNewEmptyPSystem());
                SynchornizeAllViews();
            }

            // ------------------------------------------------------------------------------------
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("fileOpen"))
            {
                CreateEditorFormForSolution(OpenProject());
                SynchornizeAllViews();
            }

            // ------------------------------------------------------------------------------------
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("toolsBuild"))
            {
                if (WorkSpace.Instance.SelectedProject == null)
                {
                    FrmMessageBox.ShowError("PSystem is not selected");
                    return;
                }
                /*
                if (!WorkSpace.Instance.SelectePSystem.CalculateNextPath())
                {
                    FrmMessageBox.ShowInfo("No more paths to calculate!");
                }
                */
            }

            // ------------------------------------------------------------------------------------
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("fileSave"))
            {
                if (WorkSpace.Instance.SelectedProject == null)
                {
                    return;
                }

                ((CurrentConfiguration)WorkSpace.Instance.SelectedProject.EditorForm).SaveProject();
            }

            // ------------------------------------------------------------------------------------
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("fileSaveAs"))
            {
                if (WorkSpace.Instance.SelectedProject == null)
                {
                    return;
                }

                ((CurrentConfiguration)WorkSpace.Instance.SelectedProject.EditorForm).SaveProjectAs();
            }
            
            // ------------------------------------------------------------------------------------
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("viewNavigation"))
            {
                ((ToolStripMenuItem)sender).Checked = !((ToolStripMenuItem)sender).Checked;
                if (((ToolStripMenuItem)sender).Checked)
                {
                    _navigationForm = new CurrentConfigurationTree();
                    _navigationForm.FormClosed += _navigationForm_FormClosed;
                    _navigationForm.Show(dockPanel1, DockState.DockLeft);
                }
                else if (_navigationForm != null)
                {
                    _navigationForm.FormClosed -= _navigationForm_FormClosed;
                     _navigationForm.Close();
                   _navigationForm.Dispose();
                    _navigationForm = null;
                }
            }

            // ------------------------------------------------------------------------------------
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("viewSolutions"))
            {
                ((ToolStripMenuItem)sender).Checked = !((ToolStripMenuItem)sender).Checked;
                if (((ToolStripMenuItem)sender).Checked)
                {
                    _solutionsForm = new AvailableTransitions();
                    _solutionsForm.FormClosed += _solutionsForm_FormClosed;
                    _solutionsForm.NotifySolutionsSelection += _solutionsForm_NotifySolutionsSelection;
                    _solutionsForm.Show(dockPanel1, DockState.DockRight);
                    // _solutionsForm.UpdatePsystemSelection();
                }
                else if (_solutionsForm != null)
                {
                    _solutionsForm.FormClosed -= _solutionsForm_FormClosed;
                    _solutionsForm.NotifySolutionsSelection -= _solutionsForm_NotifySolutionsSelection;
                    _solutionsForm.Close();
                    _solutionsForm.Dispose();
                    _solutionsForm = null;
                }
            }

            // ------------------------------------------------------------------------------------
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("viewComputationTree"))
            {
                ((ToolStripMenuItem)sender).Checked = !((ToolStripMenuItem)sender).Checked;
                if (((ToolStripMenuItem)sender).Checked)
                {
                    _computationTree = new ComputationTree(this);
                    _computationTree.FormClosed += ComputationTreeFormClosed;
                    _computationTree.Show(dockPanel1, DockState.DockRight);
                }
                else if (_computationTree != null)
                {
                    _computationTree.FormClosed -= ComputationTreeFormClosed;
                    _computationTree.Close();
                    _computationTree.Dispose();
                    _computationTree = null;
                }
            }

            // ------------------------------------------------------------------------------------
            #region View->Logs
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("viewLogs"))
            {
                ((ToolStripMenuItem)sender).Checked = !((ToolStripMenuItem)sender).Checked;
                if (((ToolStripMenuItem)sender).Checked)
                {
                    _logsView = new LogsView();
                    _logsView.FormClosed += _logsView_FormClosed;
                    _logsView.Show(dockPanel1, DockState.DockBottomAutoHide);
                }
                else if (_logsView != null)
                {
                    _logsView.FormClosed -= _logsView_FormClosed;
                    _logsView.Close();
                    _logsView.Dispose();
                }
            }
            #endregion

            // ------------------------------------------------------------------------------------
            #region View->Generated Language
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("viewGeneratedLanguage"))
            {
                ((ToolStripMenuItem)sender).Checked = !((ToolStripMenuItem)sender).Checked;
                if (((ToolStripMenuItem)sender).Checked)
                {
                    _generatedLanguageView = new GeneratedLanguageView();
                    _generatedLanguageView.FormClosed += _generatedLanguageView_FormClosed;
                    _generatedLanguageView.Show(dockPanel1, DockState.DockBottomAutoHide);
                }
                else if (_generatedLanguageView != null)
                {
                    _generatedLanguageView.FormClosed -= _generatedLanguageView_FormClosed;
                    _generatedLanguageView.Close();
                    _generatedLanguageView.Dispose();
                }
            }
            #endregion

            
            // ------------------------------------------------------------------------------------
            #region View->Generated Language
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("viewConfigurationDiff"))
            {
                ((ToolStripMenuItem)sender).Checked = !((ToolStripMenuItem)sender).Checked;
                if (((ToolStripMenuItem)sender).Checked)
                {
                    _configDiffView = new ConfigDiffsView();
                    _configDiffView.FormClosed += _configDiffView_FormClosed;
                    _configDiffView.Show(dockPanel1, DockState.DockBottomAutoHide);
                }
                else if (_configDiffView != null)
                {
                    _configDiffView.FormClosed -= _configDiffView_FormClosed;
                    _configDiffView.Close();
                    _configDiffView.Dispose();
                    _configDiffView = null;
                }
            }
            #endregion

            // ------------------------------------------------------------------------------------
            #region Help->About
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("helpAbout"))
            {
                FrmMessageBox.ShowInfo("Strings pSystem Simulator. IMI 2011 (c) ");
            }
            #endregion
            // ------------------------------------------------------------------------------------
            #region File->Export Image
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("fileExportImage"))
            {
                if (WorkSpace.Instance.SelectedProject != null &&
                    WorkSpace.Instance.SelectedProject.EditorForm != null)
                {
                    var editorForm = WorkSpace.Instance.SelectedProject.EditorForm as CurrentConfiguration;
                    editorForm.ExportToImage();
                }
            }
            #endregion
            // ------------------------------------------------------------------------------------
            #region File->Open Test
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("fileOpenTest"))
            {
                var fbd = new FolderBrowserDialog();
                String selectedProjectLocation = @"F:\Membrane_computing_Tema_Rogojin\String_Objects\Simuleator_2011\configurations_with_variants";
                fbd.ShowNewFolderButton = false;
                fbd.Description = "Select test project location to autoload";
                /*
                if(fbd.ShowDialog() != DialogResult.OK)
                {
                    return;
                }
                selectedProjectLocation = fbd.SelectedPath;
                */
                
                var pSystemForm = new CurrentConfiguration();
                pSystemForm.OpenTestProject(selectedProjectLocation);

                if (WorkSpace.Instance.SelectedProject != null)
                {
                    WorkSpace.Instance.SelectedProject.EditorForm = pSystemForm;
                    pSystemForm.Project = WorkSpace.Instance.SelectedProject;

                    pSystemForm.Closing += new System.ComponentModel.CancelEventHandler(pSystemForm_Closing);
                    pSystemForm.Activated += new EventHandler(pSystemForm_Activated);
                    pSystemForm.NotifyMembraneSelection += new elements.MembraneG.MmebraneSelectionHandler(pSystemForm_NotifyMembraneSelection);

                    // register project in the system, and show form
                    WorkSpace.Instance.Projects.Add(WorkSpace.Instance.SelectedProject);
                    pSystemForm.Show(dockPanel1);
                    
                    
                    if (_solutionsForm != null && WorkSpace.Instance.SelectedProject != null)
                    {
                        _solutionsForm.UpdatePsystemSelection(WorkSpace.Instance.SelectedProject.EditorForm, null);
                    }

                    if (_computationTree != null  && WorkSpace.Instance.SelectedProject != null)
                    {
                        _computationTree.UpdateComputationTree(WorkSpace.Instance.SelectedProject);
                    }


                }
                

            }
            #endregion
            // ------------------------------------------------------------------------------------
            #region Tools->Step
     
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("toolsStep"))
            {
                if (WorkSpace.Instance.SelectedProject == null ||
                    !((PSystemsTree) WorkSpace.Instance.SelectedProject).CalculateLeafPaths())
                   // !WorkSpace.Instance.SelectedProject.ApplyAllSolutions(WorkSpace.Instance.SelectedProject))
                {
                    FrmMessageBox.ShowInfo("No more solutions to apply (configuration halted)");
                }
                else
                {
                    if (_solutionsForm != null && WorkSpace.Instance.SelectedProject != null)
                    {
                        _solutionsForm.UpdatePsystemSelection(WorkSpace.Instance.SelectedProject.EditorForm, null);
                    }

                    if (_computationTree != null && WorkSpace.Instance.SelectedProject != null)
                    {
                        _computationTree.UpdateComputationTree(WorkSpace.Instance.SelectedProject);
                    }

                    LogsView.Info("One step performed (all solutions were applyed)");
                }
            }
            #endregion

            #region Tools Run
            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("toolsRunInParallel"))
            {
                calculateAllPaths(WorkSpace.Instance.SelectedProject, true);
            }

            if (((ToolStripMenuItem)sender).Tag.ToString().Equals("toolsRunSequencial"))
            {
                calculateAllPaths(WorkSpace.Instance.SelectedProject, false);
            }

            #endregion

        }
        #endregion

        #region Run solutions



        private delegate void PerformAsyncOperationDelegate(bool success, bool runInParallel, FrmOperationProgress progressForm, PSystemsTree selectedProject);

        /// <summary>
        ///     This will run an asynchronous task. This async task can be interrupted
        /// at any time, by setting selectedProject.IsAllowedToRun to false.
        /// </summary>
        /// <param name="selectedProject"></param>
        /// <param name="runInParallel"></param>
        private void calculateAllPaths(PSystemsTree selectedProject, bool runInParallel)
        {
            try
            {
                if (!IsDisposed && IsHandleCreated)
                {
                    var progressForm = new FrmOperationProgress(selectedProject);
                    BeginInvoke(new PerformAsyncOperationDelegate(PerformAsyncOperation), new object[] { true, runInParallel, progressForm, selectedProject });
                    progressForm.ShowDialog();
                }
            }
            catch (Exception ex)
            {
                BeginInvoke(new PerformAsyncOperationDelegate(PerformAsyncOperation), new object[] { false, false, null, selectedProject });
                FrmMessageBox.ShowError("Failed to execute async operation", ex);
            }


        }

        private void PerformAsyncOperation(bool success, bool runInParallel, FrmOperationProgress progressForm, PSystemsTree selectedProject)
        {
            try
            {
                if (success)
                {
                    var startDate = DateTime.Now;
                    if (runInParallel)
                        selectedProject.ParallelCalculateLeafPaths();
                    else
                        selectedProject.CalculateLeafPaths();

                    if (progressForm != null)
                        progressForm.SetOperationComplete();


                    var endDate = DateTime.Now;

                    StringBuilder sb = new StringBuilder("");
                    sb.AppendFormat("Operation completed in {0} seconds", endDate - startDate);
                    FrmMessageBox.ShowInfo(sb.ToString());
                }
                else
                {
                    selectedProject.IsAllowedToRun = false;
                }
            }
            catch (Exception ex)
            {
                if (progressForm != null) progressForm.Close();
                FrmMessageBox.ShowError("Failed to execute async operation", ex);
            }

        }

        #endregion

        #region Views synchronization
        /// <summary>
        ///     All views are going to load the same projects
        /// </summary>
        private void SynchornizeAllViews()
        {
            if (WorkSpace.Instance.SelectedProject != null)
            {
                UpdateApplicationTitle(WorkSpace.Instance.SelectedProject.ProjectFileName);
            }

            if (_solutionsForm != null && WorkSpace.Instance.SelectedProject != null)
            {
                _solutionsForm.UpdatePsystemSelection(WorkSpace.Instance.SelectedProject.EditorForm, null);
            }

            if (_computationTree != null && WorkSpace.Instance.SelectedProject != null)
            {
                _computationTree.UpdateComputationTree(WorkSpace.Instance.SelectedProject);
            }
        }
        #endregion

        #region File operations
        /// <summary>
        ///     Open project from XML file
        /// </summary>
        /// <returns></returns>
        private PSystemsTree OpenProject()
        {
            var openDialog = new OpenFileDialog
            {
                Title = "Open pSystem  ",
                Filter = "ProjectFiles (*.pxml)|*.pxml|All files (*.*)|*.* "
            };

            // open current pSystem from a file
            if (openDialog.ShowDialog() != DialogResult.OK)
            {
                return null;
            }

            if (!File.Exists(openDialog.FileName))
            {
                FrmMessageBox.ShowError("File does not exists : " + openDialog.FileName);
                return null;
            }

            try
            {
                
                return WorkSpace.Instance.ImportFromXml(openDialog.FileName);

            }
            catch (Exception ex)
            {
                // Logger.Instance.Error(ex);
                FrmMessageBox.ShowError("Failed to de-serialize from XML", ex);
            }

            return null;
        }
        #endregion

        #region Operate on solutions
        /// <summary>
        ///     The method takes the passed configuration and creates an Editor form
        /// with all events setup.
        /// </summary>
        /// <param name="config"></param>
        public void CreateEditorFormForSolution(PSystemsTree config)
        {
            if (config == null)
            {
                return;
            }

            UpdateApplicationTitle(config.ProjectFileName);
            
            var pSystemForm = new CurrentConfiguration();
    

            WorkSpace.Instance.SelectedProject = config;
            WorkSpace.Instance.SelectedProject.BaseLabel = WorkSpace.Instance.SelectedProject.Label;
            
            WorkSpace.Instance.SelectedProject.EditorForm = pSystemForm;
            pSystemForm.Project = WorkSpace.Instance.SelectedProject;

            pSystemForm.Closing += new System.ComponentModel.CancelEventHandler(pSystemForm_Closing);
            pSystemForm.Activated += new EventHandler(pSystemForm_Activated);
            pSystemForm.NotifyMembraneSelection += new elements.MembraneG.MmebraneSelectionHandler(pSystemForm_NotifyMembraneSelection);

            pSystemForm.UpdateProjectName(config.ProjectName);
            pSystemForm.Show(dockPanel1);
        }
        #endregion

        #region Interform communication

        /// <summary>
        ///     Set application main form title, according to project name and opened file name
        /// </summary>
        /// <param name="formTitle"></param>
        public void UpdateApplicationTitle (String formTitle)
        {
            if (String.IsNullOrEmpty(formTitle))
            {
                Text = String.Format("{0} file://Untitled", APPLICATION_NAME);
            }
            else
            {
                Text = String.Format("{0} {1}", APPLICATION_NAME, formTitle);
            }
        }

        
        /// <summary>
        ///     Triggered when form is loaded. Show all tools views
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            _navigationForm = new CurrentConfigurationTree();
            _navigationForm.FormClosed += new FormClosedEventHandler(_navigationForm_FormClosed);
            _navigationForm.Show(dockPanel1, DockState.DockLeft);

            _solutionsForm = new AvailableTransitions();
            _solutionsForm.FormClosed += new FormClosedEventHandler(_solutionsForm_FormClosed);
            _solutionsForm.Show(dockPanel1, DockState.DockRight);
            _solutionsForm.NotifySolutionsSelection += _solutionsForm_NotifySolutionsSelection;

            _computationTree = new ComputationTree(this);
            _computationTree.FormClosed += ComputationTreeFormClosed;
            _computationTree.Show(dockPanel1, DockState.DockRight);

            _logsView = new LogsView();
            _logsView.FormClosed += _logsView_FormClosed;
            _logsView.Show(dockPanel1, DockState.DockBottomAutoHide);
            WorkSpace.Instance.MessagesManager.RegisterListener(_logsView);

            _generatedLanguageView = new GeneratedLanguageView();
            _generatedLanguageView.FormClosed += _generatedLanguageView_FormClosed;
            _generatedLanguageView.Show(dockPanel1, DockState.DockBottomAutoHide);
            WorkSpace.Instance.MessagesManager.RegisterListener(_generatedLanguageView);


            _configDiffView = new ConfigDiffsView();
            _configDiffView.FormClosed += _configDiffView_FormClosed;
            _configDiffView.Show(dockPanel1, DockState.DockBottomAutoHide);
            WorkSpace.Instance.MessagesManager.RegisterListener(_configDiffView);
        }

        private void _configDiffView_FormClosed(object sender, FormClosedEventArgs e)
        {
            WorkSpace.Instance.MessagesManager.UnregisterListener(_configDiffView);
            _configDiffView.Dispose();
            _configDiffView = null;
        }

        private void _generatedLanguageView_FormClosed(object sender, FormClosedEventArgs e)
        {
            WorkSpace.Instance.MessagesManager.UnregisterListener(_generatedLanguageView);
            _generatedLanguageView.Dispose();
            _generatedLanguageView = null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ComputationTreeFormClosed(object sender, FormClosedEventArgs e)
        {
            _computationTree = null;
        }

        /// <summary>
        ///     For active pSystem, send the message to highlight involved sring object
        /// </summary>
        /// <param name="solution"></param>
        private void _solutionsForm_NotifySolutionsSelection(List<Solution> solution)
        {
            if (WorkSpace.Instance.SelectedProject != null && WorkSpace.Instance.SelectedProject.EditorForm != null)
            {
                var form = WorkSpace.Instance.SelectedProject.EditorForm as CurrentConfiguration;
                if (form != null)
                {
                    form.HiglightSelectedSolutions(solution);
                }

                // search for a Configuration which has originator Solution the parameter
                // and show this System,
                SelectNewObjectsInMembrane(solution, WorkSpace.Instance.SelectedProject);
            }
        }

        private PSystemsTree SelectNewObjectsInMembrane(List<Solution> solution, PSystemsTree selectedProject)
        {
            if (solution == null || solution.Count == 0 || selectedProject == null ||
                selectedProject.SourceSolution == null)
            {
                return null;
            }


            /*
            foreach (var sol in solution)
            {
                foreach (var solution1 in selectedProject.SourceSolution)
                {
                    if(sol.)
                    
                }
            }
             */

            return null;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="editorForm"></param>
        public void SelectActiveProjectByEditorForm(Form editorForm)
        {
            if (editorForm == null || WorkSpace.Instance.Projects == null)
                return;
            foreach (var project in WorkSpace.Instance.Projects)
            {
                if (project != null && project.EditorForm == editorForm)
                {
                    WorkSpace.Instance.SelectedProject = project;
                    // TODO: Notify all other that active project has been changed
                    Debug.WriteLine("Project updated!");

                    break;
                }
            }

        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="message"></param>
        /// <param name="keys"></param>
        /// <returns></returns>
        protected override bool ProcessCmdKey(ref Message message, Keys keys)
        {
            if (

                    ((int)keys == 37) ||    // left
                    ((int)keys == 38) ||    // up
                    ((int)keys == 39) ||    // right
                    ((int)keys == 40)       // down
                )
            {
                // send keystroke to active membrane
                if (WorkSpace.Instance.SelectedProject != null &&
                    WorkSpace.Instance.SelectedProject.EditorForm != null)
                {
                    var editorForm = WorkSpace.Instance.SelectedProject.EditorForm as CurrentConfiguration;
                    editorForm.SendKeyPressToMembranes(MapCmdKeyToStandarKeyCode((int)keys));
                }
            }

            return base.ProcessCmdKey(ref message, keys);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="keyCode"></param>
        /// <returns></returns>
        private Keys MapCmdKeyToStandarKeyCode(int keyCode)
        {
            switch (keyCode)
            {
                case 37:    // left
                    return Keys.Left;
                case 38:
                    return Keys.Up;
                case 39:
                    return Keys.Right;
                case 40:
                    return Keys.Down;
                default:
                    return Keys.None;
            }
        }
        private void _solutionsForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            _solutionsForm = null;
        }

        private void _logsView_FormClosed(object sender, FormClosedEventArgs e)
        {
            _logsView = null;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _navigationForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            _navigationForm = null;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pSystemForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (_navigationForm != null && !_navigationForm.IsDisposed)
            {
                // TODO: Confirm closing
                _navigationForm.UpdatePsystemSelection(null, null);
            }

            if (_solutionsForm != null && !_solutionsForm.IsDisposed)
            {
                _solutionsForm.UpdatePsystemSelection(null, null);
            }
        }

        /// <summary>
        ///     Called when a pSystem editor is selected
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pSystemForm_Activated(object sender, EventArgs e)
        {
            // show navigation
            if (_navigationForm != null && !_navigationForm.IsDisposed)
            {
                _navigationForm.UpdatePsystemSelection(sender, e);
            }

            // show available solutions
            if (_solutionsForm != null && !_solutionsForm.IsDisposed)
            {
                _solutionsForm.UpdatePsystemSelection(sender, e);
            }
        }

        /// <summary>
        ///     Called when a membrane is selected in active editor
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="membrane"></param>
        private void pSystemForm_NotifyMembraneSelection(elements.MembraneG sender, Membrane membrane)
        {
            if (_navigationForm != null && !_navigationForm.IsDisposed)
            {
                _navigationForm.UpdateMembraneSelection(sender, membrane);
            }

            if (_solutionsForm != null && !_solutionsForm.IsDisposed)
            {
                _solutionsForm.UpdateMembraneSelection(sender, membrane);
            }
        }

        /// <summary>
        ///     Handle 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dockPanel1_ActiveContentChanged(object sender, EventArgs e)
        {
            Console.WriteLine("ActiveContentChanged: Triggered!");

            var dockPanel = sender as DockPanel;
            if (dockPanel != null && dockPanel.ActiveDocument != null)
            {
                var editorForm = dockPanel.ActiveDocument as Editor.CurrentConfiguration;
                if (editorForm != null)
                {
                    WorkSpace.Instance.SelectedProject = editorForm.Project;
                    SynchornizeAllViews();
                }
            }
        }

        public ConfigDiffsView DiffView
        {
            get
            {
                if(_configDiffView == null)
                {
                    _configDiffView = new ConfigDiffsView();
                    _configDiffView.FormClosed += _configDiffView_FormClosed;
                    _configDiffView.Show(dockPanel1, DockState.DockBottomAutoHide);
                }
                return _configDiffView;
            }
        }

        #endregion Interform communication
    }
}